개요
Timefit 예약 관리 시스템의 업체 정보 관리, 영업시간 설정, 예약 가능 시간 슬롯 관리를 위한 API입니다. 업체 프로필 관리, 서비스 메뉴 설정, 운영 시간 관리 기능을 제공합니다.
API 목록
구분 | API 명 | 설명 |
---|---|---|
프로필 관리 | 업체 정보 조회 | 업체의 프로필 정보를 조회합니다 |
프로필 관리 | 업체 정보 수정 | 업체의 프로필 정보를 수정합니다 |
운영 관리 | 영업시간 설정 | 업체의 영업시간을 설정합니다 |
운영 관리 | 영업시간 조회 | 업체의 영업시간을 조회합니다 |
예약 관리 | 예약 가능 시간 설정 | 예약 가능한 시간대를 설정합니다 |
예약 관리 | 예약 가능 시간 조회 | 예약 가능한 시간대를 조회합니다 |
서비스 관리 | 서비스 메뉴 등록 | 제공하는 서비스/메뉴를 등록합니다 |
서비스 관리 | 서비스 메뉴 조회 | 등록된 서비스/메뉴를 조회합니다 |
서비스 관리 | 서비스 메뉴 수정 | 서비스/메뉴 정보를 수정합니다 |
서비스 관리 | 서비스 메뉴 삭제 | 서비스/메뉴를 삭제합니다 |
1. 업체 정보 조회
업체의 프로필 정보를 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/businesses/{businessId}/profile \\
-H "Authorization: Bearer {accessToken}"
메서드 | 요청 URL |
---|---|
GET | https://{SERVER_URL}/api/businesses/{businessId}/profile |
Request Header
파라미터 | 타입 | 필수여부 | 설명 |
---|---|---|---|
Authorization | String | 필수 | Bearer |
Path Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
businessId | string | Y | 비즈니스 ID (UUID) | 660e8400-e29b-41d4-a716-446655440001 |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "업체 정보 조회가 완료되었습니다",
"data": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"businessType": "미용실",
"businessNumber": "123-45-67890",
"address": "서울시 강남구 테헤란로 123",
"contactPhone": "0212345678",
"description": "깔끔하고 세련된 미용실입니다",
"logoUrl": "<https://example.com/logo.jpg>",
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z",
"members": [
{
"userId": "550e8400-e29b-41d4-a716-446655440000",
"email": "business@example.com",
"name": "홍길동",
"phoneNumber": "01012345678",
"profileImageUrl": "<https://example.com/profile.jpg>",
"role": "OWNER",
"joinedAt": "2024-06-07T12:30:00Z",
"invitedBy": null,
"isActive": true
},
{
"userId": "551e8400-e29b-41d4-a716-446655440002",
"email": "manager@example.com",
"name": "김매니저",
"phoneNumber": "01087654321",
"profileImageUrl": null,
"role": "MANAGER",
"joinedAt": "2024-06-10T15:20:00Z",
"invitedBy": "550e8400-e29b-41d4-a716-446655440000",
"isActive": true
}
],
"userRole": "OWNER"
}
}
Response Elements
필드 | 타입 | 필수여부 | 설명 |
---|---|---|---|
businessId | string | 필수 | 업체 ID (UUID) |
businessName | string | 필수 | 상호명 |
businessType | string | 선택 | 업종 |
businessNumber | string | 필수 | 사업자번호 |
address | string | 선택 | 업체 주소 |
contactPhone | string | 선택 | 업체 연락처 |
description | string | 선택 | 업체 설명 |
logoUrl | string | 선택 | 로고 이미지 URL |
createdAt | string | 필수 | 업체 등록일시 (ISO 8601) |
updatedAt | string | 필수 | 업체 수정일시 (ISO 8601) |
members | array | 필수 | 업체 구성원 목록 |
members[].userId | string | 필수 | 사용자 ID |
members[].email | string | 필수 | 사용자 이메일 |
members[].name | string | 필수 | 사용자 이름 |
members[].phoneNumber | string | 선택 | 사용자 연락처 |
members[].profileImageUrl | string | 선택 | 프로필 이미지 URL |
members[].role | string | 필수 | 업체 내 역할 (OWNER, MANAGER, MEMBER) |
members[].joinedAt | string | 필수 | 참여일시 |
members[].invitedBy | string | 선택 | 초대자 사용자 ID |
members[].isActive | boolean | 필수 | 활성화 상태 |
userRole | string | 필수 | 요청자의 해당 업체에서의 역할 |
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
BUSINESS_NOT_FOUND | 404 | "업체 정보를 찾을 수 없습니다" | 존재하지 않는 업체 |
ACCESS_DENIED | 403 | "접근 권한이 없습니다" | 업체 구성원이 아님 |
TOKEN_EXPIRED | 401 | "토큰이 만료되었습니다" | JWT 토큰 만료 |
TOKEN_INVALID | 401 | "유효하지 않은 토큰입니다" | JWT 토큰 검증 실패 |
2. 업체 정보 수정
업체의 프로필 정보를 수정합니다.
Request
Request Syntax
curl -X PUT https://{SERVER_URL}/api/businesses/{businessId}/profile \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"businessName": "홍길동 프리미엄 미용실",
"businessType": "미용실",
"address": "서울시 강남구 테헤란로 456",
"contactPhone": "0287654321",
"description": "최고급 서비스를 제공하는 프리미엄 미용실입니다",
"logoUrl": "<https://example.com/new-logo.jpg>"
}'
메서드 | 요청 URL |
---|---|
PUT | https://{SERVER_URL}/api/businesses/{businessId}/profile |
Request Header
파라미터 | 타입 | 필수여부 | 설명 |
---|---|---|---|
Authorization | String | 필수 | Bearer |
Content-Type | String | 필수 | application/json |
Path Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
businessId | string | Y | 비즈니스 ID (UUID) | 660e8400-e29b-41d4-a716-446655440001 |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 | 제약사항 |
---|---|---|---|---|---|
businessName | string | N | 상호명 | 홍길동 프리미엄 미용실 | 2자 이상 |
businessType | string | N | 업종 | 미용실 | - |
address | string | N | 사업장 주소 | 서울시 강남구... | 200자 이하 |
contactPhone | string | N | 업체 대표 연락처 | 0287654321 | - |
description | string | N | 업체 설명 | 최고급 서비스를... | 1000자 이하 |
logoUrl | string | N | 로고 이미지 URL | https://example.com... | URL 형식 |
Response
Response Syntax (200 OK)
업체 정보 조회와 동일한 응답 구조를 반환합니다.
Error Response
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
BUSINESS_NOT_FOUND | 404 | "업체 정보를 찾을 수 없습니다" | 존재하지 않는 업체 |
ACCESS_DENIED | 403 | "접근 권한이 없습니다" | OWNER 또는 MANAGER 권한 필요 |
VALIDATION_ERROR | 400 | "입력값이 올바르지 않습니다" | 필드 검증 실패 |
BUSINESS_NUMBER_ALREADY_EXISTS | 409 | "이미 등록된 사업자번호입니다" | 사업자번호 중복 (변경 시) |
3. 영업시간 조회
업체의 영업시간을 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/businesses/{businessId}/hours \\
-H "Authorization: Bearer {accessToken}"
메서드 | 요청 URL |
---|---|
GET | https://{SERVER_URL}/api/businesses/{businessId}/hours |
Path Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
businessId | string | Y | 비즈니스 ID (UUID) | 660e8400-e29b-41d4-a716-446655440001 |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "영업시간 조회가 완료되었습니다",
"data": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"businessHours": [
{
"hourId": "cc0e8400-e29b-41d4-a716-446655440007",
"dayOfWeek": 1,
"dayName": "월요일",
"openTime": "09:00",
"closeTime": "18:00",
"isClosed": false,
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z"
},
{
"hourId": "dd0e8400-e29b-41d4-a716-446655440008",
"dayOfWeek": 0,
"dayName": "일요일",
"openTime": null,
"closeTime": null,
"isClosed": true,
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z"
}
]
}
}
Response Elements
필드 | 타입 | 필수여부 | 설명 |
---|---|---|---|
hourId | string | 필수 | 영업시간 ID (UUID) |
dayOfWeek | integer | 필수 | 요일 (0=일요일, 1=월요일, ..., 6=토요일) |
dayName | string | 필수 | 요일명 |
openTime | string | 선택 | 영업 시작 시간 (HH:mm) |
closeTime | string | 선택 | 영업 종료 시간 (HH:mm) |
isClosed | boolean | 필수 | 휴무 여부 |
4. 영업시간 설정
업체의 영업시간을 설정합니다.
Request
Request Syntax
curl -X PUT https://{SERVER_URL}/api/businesses/{businessId}/hours \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"businessHours": [
{
"dayOfWeek": 1,
"openTime": "09:00",
"closeTime": "18:00",
"isClosed": false
},
{
"dayOfWeek": 0,
"openTime": null,
"closeTime": null,
"isClosed": true
}
]
}'
메서드 | 요청 URL |
---|---|
PUT | https://{SERVER_URL}/api/businesses/{businessId}/hours |
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 | 제약사항 |
---|---|---|---|---|---|
businessHours | array | Y | 영업시간 목록 | [] | 요일별 설정 |
businessHours[].dayOfWeek | integer | Y | 요일 | 1 | 0~6 (0=일요일) |
businessHours[].openTime | string | N | 영업 시작 시간 | 09:00 | HH:mm 형식 |
businessHours[].closeTime | string | N | 영업 종료 시간 | 18:00 | HH:mm 형식 |
businessHours[].isClosed | boolean | Y | 휴무 여부 | false | - |
Response
Response Syntax (200 OK)
영업시간 조회와 동일한 응답 구조를 반환합니다.
5. 예약 가능 시간 조회
업체의 예약 가능한 시간대를 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/businesses/{businessId}/available-slots?date=2024-06-15 \\
-H "Authorization: Bearer {accessToken}"
메서드 | 요청 URL |
---|---|
GET | https://{SERVER_URL}/api/businesses/{businessId}/available-slots |
Query Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
date | string | Y | 조회할 날짜 | 2024-06-15 |
serviceId | string | N | 특정 서비스 ID | aa0e8400-e29b-41d4... |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "예약 가능 시간 조회가 완료되었습니다",
"data": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"date": "2024-06-15",
"dayOfWeek": 6,
"isBusinessOpen": true,
"businessHours": {
"openTime": "09:00",
"closeTime": "18:00"
},
"availableSlots": [
{
"slotId": "ee0e8400-e29b-41d4-a716-446655440010",
"startTime": "09:00",
"endTime": "09:30",
"duration": 30,
"capacity": 1,
"currentBookings": 0,
"isAvailable": true,
"price": null
},
{
"slotId": "ff0e8400-e29b-41d4-a716-446655440011",
"startTime": "09:30",
"endTime": "10:00",
"duration": 30,
"capacity": 1,
"currentBookings": 1,
"isAvailable": false,
"price": null
}
]
}
}
6. 예약 가능 시간 설정
업체의 예약 가능한 시간대를 설정합니다.
Request
Request Syntax
curl -X PUT https://{SERVER_URL}/api/businesses/{businessId}/available-slots \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"date": "2024-06-15",
"slots": [
{
"startTime": "09:00",
"endTime": "09:30",
"capacity": 1,
"isAvailable": true
},
{
"startTime": "09:30",
"endTime": "10:00",
"capacity": 1,
"isAvailable": false
}
]
}'
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 | 제약사항 |
---|---|---|---|---|---|
date | string | Y | 설정할 날짜 | 2024-06-15 | YYYY-MM-DD |
slots | array | Y | 시간 슬롯 목록 | [] | - |
slots[].startTime | string | Y | 시작 시간 | 09:00 | HH:mm |
slots[].endTime | string | Y | 종료 시간 | 09:30 | HH:mm |
slots[].capacity | integer | Y | 수용 인원 | 1 | 1 이상 |
slots[].isAvailable | boolean | Y | 예약 가능 여부 | true | - |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "예약 가능 시간이 설정되었습니다",
"data": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"date": "2024-06-15",
"updatedSlots": [
{
"slotId": "ee0e8400-e29b-41d4-a716-446655440010",
"startTime": "09:00",
"endTime": "09:30",
"capacity": 1,
"isAvailable": true,
"createdAt": "2024-06-07T12:30:00Z"
}
],
"totalSlots": 16,
"availableSlots": 14,
"updatedAt": "2024-06-07T12:30:00Z"
}
}
7. 서비스 메뉴 조회
등록된 서비스/메뉴를 조회합니다.
Request
Request Syntax
curl -X GET https://{SERVER_URL}/api/businesses/{businessId}/services \\
-H "Authorization: Bearer {accessToken}"
Response
Response Syntax (200 OK)
{
"success": true,
"message": "서비스 메뉴 조회가 완료되었습니다",
"data": {
"businessId": "660e8400-e29b-41d4-a716-446655440001",
"businessName": "홍길동 미용실",
"services": [
{
"serviceId": "aa0e8400-e29b-41d4-a716-446655440005",
"serviceName": "기본 커트",
"description": "기본적인 헤어커트 서비스입니다",
"price": 25000,
"duration": 60,
"category": "기본",
"imageUrl": "<https://example.com/cut.jpg>",
"isActive": true,
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z"
},
{
"serviceId": "bb0e8400-e29b-41d4-a716-446655440006",
"serviceName": "프리미엄 염색",
"description": "고급 염색 서비스입니다",
"price": 80000,
"duration": 180,
"category": "프리미엄",
"imageUrl": "<https://example.com/color.jpg>",
"isActive": true,
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z"
}
],
"totalCount": 2,
"activeCount": 2
}
}
8. 서비스 메뉴 등록
제공하는 서비스/메뉴를 등록합니다.
Request
Request Syntax
curl -X POST https://{SERVER_URL}/api/businesses/{businessId}/services \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"serviceName": "기본 커트",
"description": "기본적인 헤어커트 서비스입니다",
"price": 25000,
"duration": 60,
"category": "기본",
"imageUrl": "<https://example.com/cut.jpg>",
"isActive": true
}'
Request Elements
필드 | 타입 | 필수 | 설명 | 예시 | 제약사항 |
---|---|---|---|---|---|
serviceName | string | Y | 서비스명 | 기본 커트 | 2자 이상 |
description | string | N | 서비스 설명 | 기본적인... | 500자 이하 |
price | integer | Y | 가격 (원) | 25000 | 0 이상 |
duration | integer | Y | 소요 시간 (분) | 60 | 15분 단위 |
category | string | N | 카테고리 | 기본 | - |
imageUrl | string | N | 서비스 이미지 URL | https://... | URL 형식 |
isActive | boolean | N | 활성화 상태 | true | 기본값: true |
Response
Response Syntax (201 Created)
{
"success": true,
"message": "서비스가 등록되었습니다",
"data": {
"serviceId": "aa0e8400-e29b-41d4-a716-446655440005",
"serviceName": "기본 커트",
"description": "기본적인 헤어커트 서비스입니다",
"price": 25000,
"duration": 60,
"category": "기본",
"imageUrl": "<https://example.com/cut.jpg>",
"isActive": true,
"displayOrder": 1,
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T12:30:00Z"
}
}
9. 서비스 메뉴 수정
서비스/메뉴 정보를 수정합니다.
Request
Request Syntax
curl -X PUT https://{SERVER_URL}/api/businesses/{businessId}/services/{serviceId} \\
-H "Authorization: Bearer {accessToken}" \\
-H "Content-Type: application/json" \\
-d '{
"serviceName": "프리미엄 커트",
"description": "프리미엄 헤어커트 서비스입니다",
"price": 35000,
"duration": 90,
"category": "프리미엄",
"imageUrl": "<https://example.com/premium-cut.jpg>",
"isActive": true
}'
Path Parameters
파라미터 | 타입 | 필수 | 설명 | 예시 |
---|---|---|---|---|
businessId | string | Y | 비즈니스 ID (UUID) | 660e8400-e29b-41d4... |
serviceId | string | Y | 서비스 ID (UUID) | aa0e8400-e29b-41d4... |
Response
Response Syntax (200 OK)
{
"success": true,
"message": "서비스 정보가 수정되었습니다",
"data": {
"serviceId": "aa0e8400-e29b-41d4-a716-446655440005",
"serviceName": "프리미엄 커트",
"description": "프리미엄 헤어커트 서비스입니다",
"price": 35000,
"duration": 90,
"category": "프리미엄",
"imageUrl": "<https://example.com/premium-cut.jpg>",
"isActive": true,
"displayOrder": 1,
"previousValues": {
"serviceName": "기본 커트",
"price": 25000,
"duration": 60
},
"createdAt": "2024-06-07T12:30:00Z",
"updatedAt": "2024-06-07T15:45:00Z"
}
}
10. 서비스 메뉴 삭제
서비스/메뉴를 삭제합니다.
Request
Request Syntax
curl -X DELETE https://{SERVER_URL}/api/businesses/{businessId}/services/{serviceId} \\
-H "Authorization: Bearer {accessToken}"
Response
Response Syntax (200 OK)
{
"success": true,
"message": "서비스가 삭제되었습니다",
"data": {
"serviceId": "aa0e8400-e29b-41d4-a716-446655440005",
"deletedAt": "2024-06-07T15:30:00Z"
}
}
권한 체계
업체 내 역할별 권한
역할 | 프로필 조회 | 프로필 수정 | 영업시간 관리 | 서비스 관리 | 멤버 관리 |
---|---|---|---|---|---|
OWNER | ✅ | ✅ | ✅ | ✅ | ✅ |
MANAGER | ✅ | ✅ | ✅ | ✅ | ❌ |
MEMBER | ✅ | ❌ | ❌ | ❌ | ❌ |
권한 체크 로직
JWT 토큰에서 사용자 ID 추출
user_business_role 테이블에서 권한 확인:
sqlSELECT role FROM user_business_role WHERE user_id = ? AND business_id = ? AND is_active = true
API별 필요 권한 검증
에러 응답
에러 코드 | 상태 코드 | 메시지 | 발생 상황 |
---|---|---|---|
BUSINESS_NOT_FOUND | 404 | "업체 정보를 찾을 수 없습니다" | 존재하지 않는 업체 |
ACCESS_DENIED | 403 | "접근 권한이 없습니다" | 권한 부족 |
INSUFFICIENT_PERMISSION | 403 | "해당 작업을 수행할 권한이 없습니다" | 역할별 권한 부족 |
USER_NOT_BUSINESS_MEMBER | 403 | "해당 업체의 구성원이 아닙니다" | 업체 구성원 아님 |
업체 관리 가이드
URL 구조 변경사항
기존 | 신규 | 변경사항 |
---|---|---|
/api/business/profile/{userId} | /api/businesses/{businessId}/profile | userId → businessId |
사용자 기준 | 비즈니스 기준 | 권한 체계 완전 변경 |
권한 체크 변경사항
기존 | 신규 |
---|---|
business.user_id = ? | user_business_role.user_id = ? AND business_id = ? |
1:1 관계 | N:M 관계 |
단순 소유권 | 역할 기반 권한 |
데이터 무결성
항목 | 설명 | 고려사항 |
---|---|---|
영업시간-슬롯 일관성 | 영업시간과 예약 슬롯 간 일관성 유지 | 영업시간 외 슬롯 방지 |
서비스 삭제 영향 | 서비스 삭제 시 관련 예약 데이터 영향 확인 | 기존 예약 보호 |
가격 변경 영향 | 가격 변경 시 기존 예약에 미치는 영향 고려 | 예약 시점 가격 유지 |
멤버 권한 변경 | 멤버 역할 변경 시 기존 작업에 미치는 영향 | 권한 변경 이력 관리 |
비즈니스 규칙
- 소유자 필수: 모든 비즈니스는 최소 1명의 OWNER 필요
- 권한 위임: OWNER만 다른 사용자를 MANAGER로 승격 가능
- 데이터 접근: 활성화된 멤버만 비즈니스 데이터 접근 가능
- 영업시간 제약: 예약 슬롯은 영업시간 내에서만 설정 가능